﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using DataAccessMock;

namespace Itau.SC.EnterpriseLib.Data
{
    public class DatabaseMock //: Itau.SC.EnterpriseLib.Data.Database
    {
        public const string ERRO_MOCK = "O XML do Mock e/ou os parâmetros de entrada estão incorretos";

        public DatabaseMock()
        {
            ParameterIn = new List<ParameterInWrapper>();
            ParameterOut = new List<ParameterOutWrapper>();
        }

        private IList<ParameterInWrapper> ParameterIn { get; set; }
        private IList<ParameterOutWrapper> ParameterOut { get; set; }

        public System.Data.Common.DbCommand GetStoredProcCommand(string storedProcedureName)
        {
            return new DbCommandMock(storedProcedureName);
        }

        #region ExecuteDataSet

        public System.Data.DataSet ExecuteDataSet(DbCommand command)
        {
            return ExecuteDataSet(command.CommandType, command.CommandText);
        }

        public DataSet ExecuteDataSet(CommandType commandType, string commandText)
        {
            try
            {
                XmlTestCaseHandler xmlHandler = new XmlTestCaseHandler();
                return xmlHandler.SearchTestCaseDataSet(GetProcedureName(commandText), this.ParameterIn);
            }
            catch (Exception) 
            {
                throw new Exception(ERRO_MOCK);
            }
        }

        public DataSet ExecuteDataSet(DbCommand command, DbTransaction transaction)
        {
            return ExecuteDataSet(command.CommandType, command.CommandText);
        }

        public DataSet ExecuteDataSet(DbTransaction transaction, CommandType commandType, string commandText)
        {
            return ExecuteDataSet(commandType, commandText);
        }

        // TODO ver como implementar parametros como array de objects
        private DataSet ExecuteDataSet(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
        {
            return ExecuteDataSet(CommandType.StoredProcedure, storedProcedureName);
        }

        // TODO ver como implementar parametros como array de objects
        private DataSet ExecuteDataSet(string storedProcedureName, params object[] parameterValues)
        {
            return ExecuteDataSet(CommandType.StoredProcedure, storedProcedureName);
        }

        #endregion

        #region ExecuteNonQuery

        public int ExecuteNonQuery(CommandType commandType, string commandText)
        {
            try
            {
                XmlTestCaseHandler xmlHandler = new XmlTestCaseHandler();

                if (this.ParameterOut != null && this.ParameterOut.Count > 0)
                {
                    return xmlHandler.SearchTestCaseParameterOut(GetProcedureName(commandText), this.ParameterIn, this.ParameterOut);
                }
                else
                {
                    return xmlHandler.SearchTestCaseRowsAffected(GetProcedureName(commandText), this.ParameterIn);
                }
            }
            catch (Exception)
            {
                throw new Exception(ERRO_MOCK);
            }
        }

        public int ExecuteNonQuery(DbCommand command)
        {
            return ExecuteNonQuery(command.CommandType, command.CommandText);
        }

        public int ExecuteNonQuery(DbCommand command, DbTransaction transaction)
        {
            return ExecuteNonQuery(command.CommandType, command.CommandText);
        }

        public int ExecuteNonQuery(DbTransaction transaction, CommandType commandType, string commandText)
        {
            return ExecuteNonQuery(commandType, commandText);
        }

        // TODO ver como implementar parametros como array de objects
        public int ExecuteNonQuery(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
        {
            return ExecuteNonQuery(CommandType.StoredProcedure, storedProcedureName);
        }

        // TODO ver como implementar parametros como array de objects
        public int ExecuteNonQuery(string storedProcedureName, params object[] parameterValues)
        {
            return ExecuteNonQuery(CommandType.StoredProcedure, storedProcedureName);
        }

        #endregion

        #region ExecuteScalar

        public object ExecuteScalar(CommandType commandType, string commandText)
        {
            try
            {
                XmlTestCaseHandler xmlHandler = new XmlTestCaseHandler();
                return xmlHandler.SearchTestCaseResult(GetProcedureName(commandText), this.ParameterIn);
            }
            catch (Exception)
            {
                throw new Exception(ERRO_MOCK);
            }
        }

        public object ExecuteScalar(DbCommand command)
        {
            return ExecuteScalar(command.CommandType, command.CommandText);
        }

        public object ExecuteScalar(DbCommand command, DbTransaction transaction)
        {
            return ExecuteScalar(command.CommandType, command.CommandText);
        }

        public object ExecuteScalar(DbTransaction transaction, CommandType commandType, string commandText)
        {
            return ExecuteScalar(commandType, commandText);
        }

        // TODO ver como implementar parametros como array de objects
        public object ExecuteScalar(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
        {
            return ExecuteScalar(CommandType.StoredProcedure, storedProcedureName);
        }

        // TODO ver como implementar parametros como array de objects
        public object ExecuteScalar(string storedProcedureName, params object[] parameterValues)
        {
            return ExecuteScalar(CommandType.StoredProcedure, storedProcedureName);
        }

        #endregion

        #region ExecuteReader

        public IDataReader ExecuteReader(DbCommand command)
        {
            try
            {
                XmlTestCaseHandler xmlHandler = new XmlTestCaseHandler();
                return xmlHandler.SearchTestCaseDataReader(GetProcedureName(command.CommandText), this.ParameterIn);
            }
            catch (Exception)
            {
                throw new Exception(ERRO_MOCK);
            }
        }

        public IDataReader ExecuteReader(DbCommand command, DbTransaction transaction)
        {
            return ExecuteReader(command);
        }

        #endregion

        public void AddOutParameter(DbCommand dbCommand, string p, DbType dbType, int p_4)
        {
            ParameterOut.Add(new ParameterOutWrapper(p, null, dbType, p_4));
        }

        public void AddInParameter(DbCommand dbCommand, string p, DbType dbType, object p_4)
        {
            ParameterIn.Add(new ParameterInWrapper(p, p_4, dbType));
        }

        public IList<ParameterOutWrapper> GetOutParameters() 
        {
            return ParameterOut;
        }

        private string GetProcedureName(string commandText)
        {
            return commandText.ToUpper().Replace("CALL", string.Empty).Replace("(", string.Empty).Replace(")", string.Empty).Replace("?", string.Empty).Replace(",", string.Empty).Trim();
        }

        public void AddCursorOutParameter(System.Data.Common.DbCommand command, string CursorName)
        {
        }

        protected void DeriveParameters(System.Data.Common.DbCommand discoveryCommand)
        {
        }
    }
}
